/*
 * Author: nicolas.bredeche(@)upmc.fr
 * Created on 2005-08-31 -- Refactored on 2014-01-06 
 */

package picoevo.core;

import picoevo.tools.Dictionary;
import picoevo.tools.Display;

public abstract class Individual extends EvolutionObject implements Cloneable, Comparable {

	// ### Data ###
	
	protected static int gId = 0;
	
	public Population _populationOwner;
	protected boolean _isEvaluated = false;
	protected double _fitness = -1;
	protected int _id=-1;

	// ### Constructor(s) ###

	public Individual ( Population __populationOwner )
	{
		updateId();
		setPopulationOwner (__populationOwner);
	}
	
	// ### Methods ###

	public void updateId() {
		_id = gId;
		gId++;
	}
	
	abstract public void init();
	
	abstract public void evaluate();
	
	public int getId ()
	{
		return this._id;
	}
	
	/**
	 * 
	 * @return return the fitness value
	 */
	public double getFitness ()
	{
		//if ( isEvaluated() )
		//	Display.critical(""+this.getClass().getName()+"::computeFitness - no evaluation.");
		return ( _fitness );		
	}	
	
	
	/*public void setFitness ( Object __o )
	{
		_fitness = ((Double)__o).doubleValue();
	}*/

	final public void setFitness ( double __d ) // TODO in future implementation, fitness should not be limited to "double"
	{
		setEvaluationFlag(true);
		this._fitness = __d;
	}
	
	/**
	 * set individual internal evaluation flag -- should be used with caution! (e.g. the population renew method uses this method)
	 * @param __value
	 */
	public void setEvaluationFlag ( boolean __value )
	{
		_isEvaluated = __value;
	}
	
	public boolean isEvaluated ()
	{
		return (_isEvaluated);
	}
	
	public void setPopulationOwner ( Population __populationSpace )
	{
		_populationOwner = __populationSpace;
		//_populationSpace.addIndividual(this);
	}

	//public abstract void setFitness( Object o );

	public Object clone ()
	{
		Individual individualClone = null;
		
		try 
		{
			individualClone = ( Individual )super.clone();
		}
		catch (CloneNotSupportedException e) 
		{
            // This should never happen
            throw new InternalError(e.toString());
		}
		
		return (individualClone);
	}

	
	// ### Other methods ###
	
	/**
	 * 
	 * @param 
    */
	public int compareTo(Object __o) 
	{ 
		double fitness1 = this.getFitness(); 
		double fitness2 = ((Individual) __o).getFitness();
		
		if ( this.getOwner().getProperties().getBooleanProperty("OptimisationFlag") == Dictionary.Maximization ) // Maximising!
		{
			if ( fitness1 > fitness2 )  
				return 1; 
			else 
				if ( fitness1 == fitness2 ) 
					return 0; 
				else 
					return -1;
		}
		else // Minimising!
		{
			if ( fitness1 > fitness2 )  
				return -1; 
			else 
				if ( fitness1 == fitness2 ) 
					return 0; 
				else 
					return 1;
		}			
	}
	
	final public Population getOwner ()
	{
		return this._populationOwner;
	}

	@Override 
	public void displayInformation()
	{
		//Display.info("## Individual Information : summary ##");
		Display.info("Individual name : " + this.getId() );
		Display.info_nocr("fitness : ");
	    if ( isEvaluated() )
	    		Display.info(""+_fitness);
	    else
    			Display.info("n/a");
	}

	
}
